﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Mail;
using System.IO;
using Common;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using jabber.client;


namespace DriverExtendedNotifications
{
    [System.AddIn.AddIn("DriverExtendedNotifications")]
    public class ExtendedNotifications : Common.ModuleBase
    {
        Port port;

        string smtpServer;
        string smtpUser;
        string smtpPassword;
        string popServer;

        string emailTarget;
        string smsTarget;

        string jabberServer;
        string jabberUser;
        string jabberPassword;
        string IMtarget;

        JabberClient j;
        

        public override void Start()
        {
            
            string[] words = moduleInfo.Args();
            j = null;
            smtpServer = words[0];
            smtpUser = words[1];
            smtpPassword = words[2];
            popServer = words[3];
            emailTarget = words[4];
            smsTarget = words[5];

            jabberServer=words[6];
            jabberUser=words[7];
            jabberPassword=words[8];
            IMtarget=words[9];



            View.VPortInfo portInfo = GetPortInfoFromPlatform("extendedNotifications");
             port = InitPort(portInfo);

            var roleList = new List<View.VRole>() { new RoleNotifications() };

            BindRoles(port, roleList, OnOperationInvoke);

            RegisterPortWithPlatform(port);
            j_Init_Client();
            
                        

        }

        public IList<View.VParamType> OnOperationInvoke(string roleName, String opName, IList<View.VParamType> parameters)
        {
            List<View.VParamType> retVals = new List<View.VParamType>();

            switch (opName)
            {
                

                case RoleNotifications.OpEmailName:
                    {
                        string subject = (string)parameters[0].Value();
                        string message = (string)parameters[1].Value();

                        List<Attachment> attachments = new List<Attachment>();

                        for (int index = 2; index < parameters.Count; index++)
                        {
                            byte[] array = (byte[])parameters[index].Value();
                            string mimeType = parameters[index].Subtype();
                            string name = parameters[index].Name();

                            Attachment attachment = new Attachment(new MemoryStream(array), name, mimeType);

                            attachments.Add(attachment);
                        }

                        bool success =  SendEmail(emailTarget, subject, message, attachments);
                        retVals.Add(new ParamType(ParamType.SimpleType.binary, "", success, "result"));
                    }
                    break;

                case RoleNotifications.OpSmsName:
                    {

                        string subject = (string)parameters[0].Value();
                        string message = (string)parameters[1].Value();

                        List<Attachment> attachments = new List<Attachment>();

                        bool success = SendEmail(smsTarget, subject, message, attachments);
                        retVals.Add(new ParamType(ParamType.SimpleType.binary, "", success, "result"));
                    }
                    break;
                
                
                
                //***** <Added : Rayman Preet, U Waterloo 

                // Operation to send IM messages/notifications to 
                case RoleNotifications.OpSendIM:
                    {

                        string message = (string)parameters[0].Value();
                        j.Message(IMtarget,message);
                        
                    }
                    break;

                // Operation to Receive IM messages from 
                case RoleNotifications.OpRxIM:
                    {
                        // This Operation can NOT be invoked
                        // this is an operation to be subscribed
                    }
                    break;

                
                // Operation to poll contents of inbox at  for any unread emails
                case RoleNotifications.OpRxEmail:
                    {
                        return RxEmail();                           
                    }


                //***** Added : Rayman Preet, U Waterloo>




                default:
                    logger.Log("Invalid operation {0}", opName);
                    break;
            }


            return retVals;
        }


        #region XMPP/Jabber Methods 
        //*************************** XMPP / JABBER stuff starts 
        //***** <Added : Rayman Preet, U Waterloo 

        public void _jabberClient_OnMessage(object sender, jabber.protocol.client.Message msg)
        {

            // Discard Keep-Alive messages & any Error messages.
            if (msg.Body == "" || !msg.Type.ToString().Equals("chat")) { return; }

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append("" + msg.Body); 
            string txt = sb.ToString();
            IList<View.VParamType> retVals = new List<View.VParamType>();

            // Contents of message put in return parameters
            retVals.Add(new ParamType(ParamType.SimpleType.text, "",txt, "message"));
            
            // Notifying modules (e.g., AppIM) subscribed to the port
            port.Notify(RoleNotifications.RoleName, RoleNotifications.OpRxIM, retVals);
        }




        private void j_OnAuthenticate(object sender)
        {
            // Do noting on authentication

            //j.Message(IMtarget,"test message"); 
        }

         private void j_OnReadText(object sender, string txt)
        {
            // ignore keep-alive spaces
            if (txt == " ") return;  

           // logger.Log("XMPP RX: " + txt);

        }



        private void j_OnError(object sender, Exception ex)
        {
            // There was an error!
            Console.WriteLine("Error: " + ex.ToString());

            // Shut down.
            j.Close();
        }


        private void j_Init_Client()
        {
            j = new JabberClient();
            j.Server = jabberServer;
            j.User = jabberUser;
            j.Password = jabberPassword;
            

            j.AutoRoster = true;
            j.AutoStartTLS = true;
            j.AutoReconnect = 30F;
            j.AutoStartCompression = true;
            j.AutoStartTLS = true;
            j.KeepAlive = 30F;
            j.LocalCertificate = null;


            j.OnMessage += new MessageHandler(_jabberClient_OnMessage);
            j.OnReadText += new bedrock.TextHandler(j_OnReadText);
            j.OnError += new bedrock.ExceptionHandler(j_OnError);
            j.OnAuthenticate += new bedrock.ObjectHandler(j_OnAuthenticate);
            //j.OnWriteText += new bedrock.TextHandler(j_OnWriteText);

            // Connect Jabber client
            j.Connect();
            
            return;
        }

        //*************************** XMPP / JABBER stuff ends

        #endregion



        #region Method to poll inbox
        private IList<View.VParamType> RxEmail()
        {
            String temp; 
            String[] response={"0","0","0"}; 
            int newmsg,basis,i;
            List<View.VParamType> retVals = new List<View.VParamType>();
            POP3Client.POP3client Demo = new POP3Client.POP3client();

            basis = 0; // change according to inbox . This is for my inbox. 
           
            logger.Log("\n Connecting to mail server(mail.com) on port 110 Response : " + Demo.connect(popServer));
            Demo.USER(smtpUser);
            Demo.PASS(smtpPassword);
            temp = Demo.STAT(); 
            logger.Log("\nSTAT Response from Mail Server is {0}",temp);
            
            if (!temp.Contains("+OK")) 
            { 
                // TODO : Attempt Re-connection to mail server
                return retVals; 
            }

            response = temp.Split(' ');
            newmsg = int.Parse(response[1]) - basis;
            logger.Log("Number of messages in inbox : {0} . Number of new messages {1}",response[1],newmsg.ToString());

            if (newmsg > 0)
            {
                
                for (i = 1; i <= newmsg; i++)
                {

                    temp = Demo.RETR(basis + i);Demo.DELE(basis + i);
                    EmailMessage m = new EmailMessage(temp);
                    
                    // Add Sender, Subject and Body of email message into respective operation return values
                    retVals.Add(new ParamType(ParamType.SimpleType.text, "string", m.GetFrom(), ""));
                    retVals.Add(new ParamType(ParamType.SimpleType.text, "string", m.GetSubject(), ""));
                    retVals.Add(new ParamType(ParamType.SimpleType.text, "string", m.GetBody(), ""));
                    
                }
             
            }

            Demo.QUIT(); 
            return retVals;
        }

        //***** Added : Rayman Preet, U Waterloo>
        #endregion


        private bool SendEmail(string toAddress, string subject, string body, List<Attachment> attachments)
        {
            MailMessage message = new MailMessage();

            message.From = new MailAddress(smtpUser);
            message.To.Add(toAddress);
            message.Subject = subject;
            message.Body = body;

            foreach (Attachment attachment in attachments)
            {
                message.Attachments.Add(attachment);
            }

            try
            {
                SmtpClient smtpClient = new SmtpClient(smtpServer, 587);// Port 587 added for sending smtp message @Rayman Preet 6/9/11 1742hrs
                smtpClient.Credentials = new System.Net.NetworkCredential(smtpUser, smtpPassword);
                smtpClient.EnableSsl = true;
                //logger.Log("Email message details : {0} , {1}", smtpUser, smtpServer);
                smtpClient.Send(message);
                smtpClient.Dispose(); // @Rayman Preet 6/9/11 1742hrs
                
            }
            catch (Exception exception)
            {
                logger.Log("Exception while sending message: {0}", exception.ToString());
                return false;
            }

            return true;
        }


        //nothing to do for these overrides
        public override void Stop() { }
        public override void PortRegistered(View.VPort port) { }
        public override void PortDeregistered(View.VPort port) { }

    }
}
